%{ open Ast %}

%token SEMI LPAREN RPAREN LBRACE RBRACE RBRACKET LBRACKET COMMA 
%token RTOKEN LTOKEN ETOKEN
%token STRUCT INT CHARS
%token OBJLINE OBJTRIANGLE OBJELLIPSE OBJRECTANGLE OBJSHAPE
%token V1 V2 V3 V4
%token PLUS MINUS TIMES DIVIDE ASSIGN
%token EQ NEQ LT LEQ GT GEQ
%token AND OR NOT LBRACKET RBRACKET
%token MEMBERINDEX SHIFT MOVETO SERIALIZED PARALLELIZED 
%token RETURN IF ELSE FOR WHILE 
%token MEMBERIN
%token <string>STRING
%token <string>RECTANGLE
%token <string>ELLIPSE
%token <string>LINE
%token <string>SHAPE
%token <int> LITERAL
%token <string> ID
%token EOF

%nonassoc NOELSE
%nonassoc ELSE
%right ASSIGN
%left EQ NEQ
%left LT GT LEQ GEQ
%left PLUS MINUS
%left TIMES DIVIDE

%start program
%type <Ast.program> program

%%

program:
   /* nothing */ { [], [] }
 | program vdecl { ($2 :: fst $1), snd $1 }
 | program fdecl { fst $1, ($2 :: snd $1) }

fdecl:
   ID LPAREN formals_opt RPAREN LBRACE vdecl_opt stmt_list RBRACE
     { { fname = $1;
	 formals = $3;
	 locals = List.rev $6;
	 body = List.rev $7 } }

formals_opt:
    /* nothing */ { [] }
  | formal_list   { List.rev $1 }

formal_list: 
    formal_decl                     { [$1] }
  | formal_list COMMA formal_decl   { $3 :: $1 } 

formal_decl:
    CHARS ID                    { { vtype = "string"; name = $2; vsize = 1} }
  | INT ID                      { { vtype = "int"; name = $2; vsize = 1} }
  | OBJRECTANGLE ID 			{ { vtype = "rect"; name = $2; vsize = 1} }
  | OBJELLIPSE ID 				{ { vtype = "ellipse"; name = $2; vsize = 1} }
  | OBJLINE ID 					{ { vtype = "line"; name = $2; vsize = 1} }
  | OBJSHAPE ID 				{ { vtype = "shape"; name = $2; vsize = 1} }

vdecl_opt:
    /* nothing */    { [] }
  | vdecl_list { List.rev $1 }

vdecl_list:
  | vdecl                       { [$1] }
  | vdecl_list vdecl         { $2 :: $1 }

vdecl:
    CHARS ID SEMI 		{ {vtype = "string"; name = $2; vsize = 1} }
  | INT ID SEMI {	 {vtype = "int"; name = $2; vsize = 1} }
  | OBJRECTANGLE ID SEMI { {vtype = "rect"; name = $2; vsize = 1} }
  | OBJELLIPSE ID SEMI   { {vtype = "ellipse"; name = $2; vsize = 1} }
  | OBJLINE ID SEMI      { {vtype = "line"; name = $2; vsize = 1} }
  | OBJSHAPE ID SEMI     { {vtype = "shape"; name = $2; vsize = 1} }
  | INT ID LBRACKET LITERAL RBRACKET SEMI { { vtype = "arrayi"; name = $2; vsize = $4} } 
  | OBJRECTANGLE ID LBRACKET LITERAL RBRACKET SEMI { { vtype = "arrayr"; name = $2; vsize = $4} } 
  | OBJELLIPSE ID LBRACKET LITERAL RBRACKET SEMI { { vtype = "arraye"; name = $2; vsize = $4} } 
  | OBJLINE ID LBRACKET LITERAL RBRACKET SEMI { { vtype = "arrayl"; name = $2; vsize = $4} } 
  | OBJSHAPE ID LBRACKET LITERAL RBRACKET SEMI { { vtype = "arrays"; name = $2; vsize = $4} } 

stmt_list:
    /* nothing */  { [] }
  | stmt_list stmt { $2 :: $1 }

stmt:
    expr SEMI { Expr($1) }
  | RETURN expr SEMI { Return($2) }
  | LBRACE stmt_list RBRACE { Block(List.rev $2) }
  | IF LPAREN expr RPAREN stmt %prec NOELSE { If($3, $5, Block([])) }
  | IF LPAREN expr RPAREN stmt ELSE stmt    { If($3, $5, $7) }
  | FOR LPAREN expr_opt SEMI expr_opt SEMI expr_opt RPAREN stmt
     { For($3, $5, $7, $9) }
  | WHILE LPAREN expr RPAREN stmt { While($3, $5) }

expr_opt:
    /* nothing */ { Noexpr }
  | expr          { $1 }

expr:
    LITERAL          { Literal($1) }
  | STRING           { String($1) }
  | RECTANGLE		 { Rectangle($1) }
  | LINE	 		 { Line($1) }
  | ELLIPSE		     { Ellipse($1) }
  | SHAPE			 { Shape($1) }
  | ID               { Id($1) }
  | expr PLUS   expr { Binop($1, Add,   $3) }
  | expr MINUS  expr { Binop($1, Sub,   $3) }
  | expr TIMES  expr { Binop($1, Mult,  $3) }
  | expr DIVIDE expr { Binop($1, Div,   $3) }
  | expr EQ     expr { Binop($1, Equal, $3) }
  | expr NEQ    expr { Binop($1, Neq,   $3) }
  | expr LT     expr { Binop($1, Less,  $3) }
  | expr LEQ    expr { Binop($1, Leq,   $3) }
  | expr GT     expr { Binop($1, Greater,  $3) }
  | expr GEQ    expr { Binop($1, Geq,   $3) }
  | ID ASSIGN expr   { Assign($1, $3) }
  | ID LPAREN actuals_opt RPAREN { Call($1, $3) }
  | LPAREN expr RPAREN { $2 }
  | ID SHIFT LBRACE expr expr RBRACE 		 {Moveby($1, $4, $5)}
  | ID MOVETO LBRACE expr expr RBRACE 		 {Moveto($1, $4, $5)}
  | ID MEMBERIN V1   { GetV1($1) }
  | ID MEMBERIN V2   { GetV2($1) }
  | ID MEMBERIN V3   { GetV3($1) }
  | ID MEMBERIN V4   { GetV4($1) }
  | ID LBRACKET expr RBRACKET { Aid($1, $3) }
  | ID LBRACKET expr RBRACKET ASSIGN expr { AAssign($1, $3, $6) }
  | RTOKEN LBRACE expr expr expr expr RBRACE  { REvaluation($3, $4, $5, $6) } 
  | ETOKEN LBRACE expr expr expr expr RBRACE  { EEvaluation($3, $4, $5, $6) } 
  | LTOKEN LBRACE expr expr expr expr RBRACE  { LEvaluation($3, $4, $5, $6) } 

actuals_opt:
    /* nothing */ { [] }
  | actuals_list  { List.rev $1 }

actuals_list:
    expr                    { [$1] }
  | actuals_list COMMA expr { $3 :: $1 }
